Wafer roughness plot

Loading BokehJS ...

1 Base function

1.1 Different \(\mu\) sampling points

Code
# 1. Read the Excel file into a DataFrame
df = pd.read_excel('data/base_function.xlsx', sheet_name=['base', 'M'])

# 2. Split the DataFrame into two separate DataFrames
base_df = df['base']
M_df = df['M'].sort_values(by='M')
# M_df = M_df[~M_df.isin([-0.002, 0.003]).any(axis=1)]
sorted_df = pd.DataFrame(columns=['mu','xaxis', 'yaxis', 'colors'])

# 3. Create x axis
xaxis = np.arange(-15.5, 16.5, 1)
plots = []

# 4. Iterate M dataframe
for i, (index, row) in enumerate(M_df.iterrows()):
    # a. Plot raw sampling data
    p = figure(title=str(f'M: {row.M}'), x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
            width = 250, height = 150)
    new_axis = xaxis - row.M
    p.line(new_axis, base_df[index], line_color='#9DD9C5', line_width=3)
    p.circle(new_axis, base_df[index], size = 4)
    vline = Span(location=0.0, dimension = 'height', line_color='#FEEED9', line_width=1)
    p.add_layout(vline)

    # b. Plot format
    p.x_range = Range1d(-7, 7)
    p.yaxis.ticker.desired_num_ticks = 4
    p = plot_format(p, "Degrees", "Intensity", "bottom_left", "8pt", "8pt", "8pt")
    plots.append(p)

    # c. Create dataframe
    sorted_df = sorted_df.append(pd.DataFrame({'mu':[row.M]*32,'xaxis':new_axis, 'yaxis':base_df[index], 'colors':new_colors[0:32]}), ignore_index=True)
    
grid_raw = gridplot(children = plots, ncols = 6, merge_tools=False)
show(grid_raw)

1.2 Base function smoothing and interpolation

Code
# 5. Create interleaved plots
interleaved_plot = figure(title='Interleaved base function', x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
            width = 700, height = 500)
smooth_plot = figure(title='Smooth base function', x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
            width = 700, height = 500)
interpolated_plot = figure(title='Inteporlated base function points', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
            width = 700, height = 500)

# a. Define base_function and smooth df's
base_function_df = sorted_df.sort_values(by='xaxis')
diff = base_function_df['xaxis'].diff()
smooth_df = base_function_df[(diff >= 0.01) | (diff.isna())]
smooth_df = smooth_df.iloc[1:]
# b. Create non-smooth and smoot curve
interleaved_plot = figure(title='Interleaved base function', x_axis_label='sampling point', y_axis_label='intensity', tooltips=[("index", "$index"), ("(x,y)", "($x, $y)")],
                          width=700, height=500)
smooth_plot = figure(title='Smooth base function', x_axis_label='sampling point', y_axis_label='intensity', tooltips=[("index", "$index"), ("(x,y)", "($x, $y)")],
                     width=700, height=500)

# c. Plot points
for (plot, df, legend, color) in [(interleaved_plot, base_function_df, 'Non-smooth base function', '#9DC3E6'), (smooth_plot, smooth_df, 'Smooth base function', '#9D6C97')]:
    # individual points
    plot.circle(df.xaxis, df.yaxis, color=df.colors, size=6)

    # smooth curve
    plot.line(df['xaxis'], df['yaxis'], line_width=4, legend=legend, color=color)

    # format
    plot.xaxis.ticker.desired_num_ticks = 15
    plot.y_range = Range1d(0, 45000)
    plot = plot_format(plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "9pt")

# d. Interpolation
x_base = np.arange(-15.5, 15.5001, 0.001)
pchip = PchipInterpolator(smooth_df['xaxis'], smooth_df['yaxis'])
y_base = pchip(x_base)

interpolated_plot.line(x=smooth_df['xaxis'], y=smooth_df['yaxis'], line_width = 5, legend = 'Smooth base function', color = '#9D6C97')
interpolated_plot.line(x_base, y_base, line_width = 5, color = '#9DD9C5', legend = 'Interpolated base function')
interpolated_plot.xaxis.ticker.desired_num_ticks = 15
interpolated_plot.y_range = Range1d(0, 45000)

interpolated_plot = plot_format(interpolated_plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "9pt")
base_function_grid = gridplot(children=[interleaved_plot, smooth_plot, interpolated_plot], ncols=3, merge_tools=False, width=420, height=350)
show(base_function_grid)

2 Rough data

Code
# This function takes an array of x values (x) and three additional parameters: a, b, and c. The a parameter scales the output of the base_function, while the b and c parameters control the shape of the fitted function. By multiplying the output of base_function by a, we can adjust the amplitude of the fitted function to match the data. The b and c parameters allow us to adjust the position and width of the fitted function to better match the data.

# When we call curve_fit, we pass in the fit_function along with the xdata and ydata arrays. The curve_fit function then adjusts the a, b, and c parameters to minimize the difference between the fitted function and the data. The function returns two values: the optimal parameter values (in the params variable), and an estimate of the covariance matrix (in the _ variable, which we ignore in this example).

# Once we have the optimal parameter values, we can evaluate the fitted function at any set of x values using:
Code
from scipy.optimize import curve_fit

# Define base function using xinterp and yinterp
def base_function(x, *params):
    return np.interp(x, x_base, y_base)

# Define function to fit to dataset1
def fit_function(x, a, b, c):
    return a * base_function(x, b, c)

# Extract xaxis and yaxis from dataset1
rough_df = pd.read_excel('data/rough_samples.xlsx')
xdata = rough_df['xaxis']
ydata = rough_df['pt2e']

# Use curve_fit to find parameters that minimize the difference between the data and the model
params, _ = curve_fit(fit_function, xdata, ydata)

# Evaluate the fitted function using the optimal parameters
yfit = fit_function(x_base, *params)

fit_plot = figure(title='Fit plot', x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
            width = 700, height = 500)

fit_plot.line(x_base, y_base, line_width = 5, color = '#9DD9C5')
# fit_plot.line(x_base, yfit, line_width = 4, color = '#9D6C97', line_dash="dotdash")
fit_plot.line(xdata, ydata, line_width = 5, color = '#9DC3E6')
fit_plot.circle(xdata, ydata, size = 8, color = '#9DC3E6', fill_color='#2F528F')
fit_plot = plot_format(fit_plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "9pt")

show(fit_plot)
Code
def fit_function(x, a):
    return a * base_function(x)

from scipy.optimize import curve_fit

xdata = rough_df['xaxis']
ydata = rough_df['pt2e']

params, _ = curve_fit(fit_function, xdata, ydata)

yfit = fit_function(x_base, *params)

fit_plot = figure(title='Fit plot', x_axis_label='sampling point', y_axis_label='intensity', tooltips = [("index", "$index"),("(x,y)", "($x, $y)")],
            width = 700, height = 500)

fit_plot.line(x_base, y_base, line_width = 4, color = '#9DD9C5', legend = 'Base function', line_dash=[10, 5])
fit_plot.line(x_base, yfit, line_width = 4, color = '#9D6C97', legend = 'pt2 fitted function', line_dash="dotdash")
fit_plot.line(xdata, ydata, line_width = 5, color = '#9DC3E6', legend_label = 'pt2 line')
fit_plot.circle(xdata, ydata, size = 10, color = '#9DC3E6', fill_color='#2F528F', legend_label = 'pt2 points')
fit_plot = plot_format(fit_plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "9pt")
show(fit_plot)
Code
from bokeh.palettes import Set3
# 1. Import data
rough_df = pd.read_excel('data/rough_samples.xlsx')
source_rough = ColumnDataSource(rough_df)

# # 2. Create plot
rough_plot = figure(x_axis_label='xaxis', y_axis_label='yaxis', width = 650, height = 400, tooltips = [("index", "$index"),("(x,y)", "($x, $y)")])
color_palette = Set3[len(rough_df.columns[1:])+1]

# a. iterate over the columns and add a line for each one
for i, col in enumerate(rough_df.columns[1:]):
    rough_plot.line('xaxis', col, source=source_rough, color = color_palette[i], legend_label = str(col), line_width=4)
    rough_plot.circle('xaxis', col, source=source_rough, color = color_palette[i], size=6)

rough_plot.line(x_base, y_base, line_width=4, color = color_palette[i+1], legend = 'Interpolated base function')
rough_plot = plot_format(rough_plot, "Degrees", "Intensity", "top_left", "10pt", "10pt", "10pt")

show(rough_plot)

3 Wafer 2 with rough areas

3.1 Calcute Aq, M and I values

Code
lendata = data.shape[0] - 1
angles = (np.linspace(0, (lendata - 1), lendata)) * (data[-1, 29] - data[-1, 28]) * (2 * np.pi / lendata / 360) + (data[-1, 28] + 9.5 + 180) * np.pi / 180
radii = (np.linspace(0, (lendata-1), lendata)) * (data[-1,31]-data[-1,30])/lendata + data[-1, 30]

Aq = []
M = []
intens = []
x = np.arange(1, 33)
datamat = data[:lendata,:] - 1

sx = np.arange(1, 32, 0.2)
for indx in range(lendata):
    # a. Do PChip spline  interpolation
    diodes = datamat[indx,:]
    pchip = PchipInterpolator(x, diodes)
    sy = pchip(sx)
    sy = 100 * sy / np.max(sy)
    c = []

    # b. Concatenation/histogram
    for indx2 in range(len(sx)):
        c.extend([indx2+1]*round(sy[indx2]))

    stddev = np.std(c) / 5
    Aq.append(1.02 * np.exp(1.987 * np.log(stddev) + 0.16))
    M.append((np.mean(c) - 1) / 5 - 15.5)
    intens.append(np.sum(sy))

3.2 Non interpolated Plot

Code
# 1. Get x and y coordinates
xvals = radii * np.cos(angles) * 1e-3
yvals = radii * np.sin(angles) * 1e-3
zvals = Aq

# 2. Clamp values to max of 3
zvalscut = 3
zvalsnew = np.array(zvals)
zvalsnew[zvalsnew > zvalscut] = zvalscut

# 3. Make a df
index = np.arange(len(xvals))
df = pd.DataFrame({
    'index':index,
    'x': xvals*1000,
    'y': yvals*1000,
    'z': zvalsnew,   
})

#| column: screen-inset-right
# 4. Rank_text
interval = alt.selection_interval()
rank_text = alt.Chart(df).mark_text(dx=20, dy=-5, align='left').encode(
    x=alt.value(10),  # x position of the text
    y=alt.value(10),  # y position of the text
    text=alt.condition(
        interval,
        alt.Text('index:Q', format='.2f'),  # display 'x' column for selected points
        alt.value('')  # display empty string for unselected points
    ),
    color=alt.value('black'), # color of the text
    fontSize = 5
)

# 5. Wafer plot
wafer_plot = alt.Chart(df).mark_circle().encode(
    x='x:Q', y='y:Q',
    color=alt.condition(
        interval,
        alt.Color('z:Q', scale=alt.Scale(scheme='turbo')),
        alt.value('lightgray')
    ),
    tooltip=['x', 'y', 'z', 'index']
).properties(height=400, width=400).add_selection(interval)

# create a table with the selected points
selected_points_table = alt.Chart(df).transform_filter(
    interval
).mark_text().encode(
    x=alt.value(0),
    y=alt.Y('row_number:O', axis=None),
    text='index:Q',
).transform_window(
    row_number='row_number()'
).properties(
    height=400,
    width=50
)

# vertically concatenate the two charts
alt.hconcat(wafer_plot, selected_points_table)
Code
sorted_df